/*
 * BehaviorParser.c
 * Profiler to classify malware into generic categories
 * @author Gregoire JACOB (gregoire.jacob@orange-ftgroup.com)
 * @date 01/12/2008
 * @version 1.0
 * Parse the behavior database stored in an XML Format
 * (relies on expat parser)
 */

#include ".\Includes\MalwareProfiler.h"

int recoverNature(char * attr){
	int i;
	static char nature[8][15] = {"none","file","folder","drive",
						         "registry","network","mail","variable"}; 
	for(i=0;i<8;i++){
		if(!strcmp(attr,nature[i])) return i;
	}
	return -1;
}

int recoverStatus(char * attr){
	if(!strcmp(attr,"created")) return 0;
	if(!strcmp(attr,"existing")) return 1;
	return -1;
}

int recoverFlow(char * attr){
	if(!strcmp(attr,"transfer")) return 0;
	if(!strcmp(attr,"single-block")) return 1;
	if(!strcmp(attr,"interleaved")) return 2;
	return -1;
}
int recoverConditional(char * attr){
	if(!strcmp(attr,"straight")) return 0;
	if(!strcmp(attr,"inverse")) return 1;
	return -1;
}



static void XMLCALL
startElement(void *data, const char *el, const char **attr){
	static current; 
	//printf("Start element: %s\n",el);
	switch(depth){
		case 0:
			if(!strcmp(el,"Behaviors")) depth++;
			break;
		case 1:
			current = 0;
			if(!strcmp(el,"Duplication")){depth++;current= INSIDE_DUP;break;}
			if(!strcmp(el,"Propagation")){depth++;current= INSIDE_PROP;break;}
			if(!strcmp(el,"Residency")){depth++;current= INSIDE_RES;break;}
			if(!strcmp(el,"Overinfection")){depth++;current= INSIDE_OVINF;break;}
			if(!strcmp(el,"ExecutionProxy")){depth++;current= INSIDE_EXEPROX;break;}
			break;
		case 2:
			switch(current){
				case INSIDE_DUP:
					if(!strcmp(el,"flow")){
						duplicationbase[nbduplication].flow = recoverFlow(attr[1]);
					}else if(!strcmp(el,"source")){
						strcpy_s(duplicationbase[nbduplication].sourcename,
							     NAME_MAX_LENGTH,attr[3]); //Name
						duplicationbase[nbduplication].sourcenature = recoverNature(attr[5]);
					}else if(!strcmp(el,"target")){
						strcpy_s(duplicationbase[nbduplication].targetname,
							     NAME_MAX_LENGTH,attr[3]); //Name
						duplicationbase[nbduplication].targetnature = recoverNature(attr[5]);
						duplicationbase[nbduplication].targetstatus = recoverStatus(attr[7]);
					}else if(!strcmp(el,"transit")){
						duplicationbase[nbduplication].transitnature = recoverNature(attr[1]);
					}
					break;
				case INSIDE_PROP:
					if(!strcmp(el,"flow")){
						propagationbase[nbpropagation].flow = recoverFlow(attr[1]);
					}else if(!strcmp(el,"source")){
						strcpy_s(propagationbase[nbpropagation].sourcename,
							     NAME_MAX_LENGTH,attr[3]); //Name
						propagationbase[nbpropagation].sourcenature = recoverNature(attr[5]);
					}else if(!strcmp(el,"interface")){
						strcpy_s(propagationbase[nbpropagation].interfacename,
							     NAME_MAX_LENGTH,attr[3]); //Name
						propagationbase[nbpropagation].interfacenature = recoverNature(attr[5]);
					}else if(!strcmp(el,"transit")){
						propagationbase[nbpropagation].transitnature = recoverNature(attr[1]);
					}
					break;
				case INSIDE_RES:
					if(!strcmp(el,"value")){
						residencybase[nbresidency].valuenature = recoverNature(attr[3]);
					}else if(!strcmp(el,"target")){
						strcpy_s(residencybase[nbresidency].targetname,
							     NAME_MAX_LENGTH,attr[3]); //Name
						residencybase[nbresidency].targetnature = recoverNature(attr[5]);
						residencybase[nbresidency].targetstatus = recoverStatus(attr[7]);
					}
					break;
				case INSIDE_OVINF:
					if(!strcmp(el,"conditional")){
						overinfectionbase[nboverinfection].conditional = recoverConditional(attr[1]);
					}else if(!strcmp(el,"marker")){
						strcpy_s(overinfectionbase[nboverinfection].markername,
							     NAME_MAX_LENGTH,attr[3]); //Name
						overinfectionbase[nboverinfection].markernature = recoverNature(attr[5]);
					}
					break;
				case INSIDE_EXEPROX:
					if(!strcmp(el,"interface")){
						strcpy_s(executionbase[nbexecution].interfacename,
							     NAME_MAX_LENGTH,attr[3]); //Name
						executionbase[nbexecution].interfacenature = recoverNature(attr[5]);
					}else if(!strcmp(el,"target")){
						strcpy_s(executionbase[nbexecution].targetname,
							     NAME_MAX_LENGTH,attr[3]); //Name
						executionbase[nbexecution].targetnature = recoverNature(attr[5]);
						executionbase[nbexecution].targetstatus = recoverStatus(attr[7]);
					}
					break;
			}//switch
					
	}//switch
}

static void XMLCALL
endElement(void *data, const char *el){
	//printf("End element: %s\n",el);
	switch(depth){
		case 1:
			if(!strcmp(el,"Behaviors")){depth--; endbehaviors = 1;}
			break;
		case 2:
			if(!strcmp(el,"Duplication")){nbduplication++;depth--;break;}
			if(!strcmp(el,"Propagation")){nbpropagation++;depth--;break;}
			if(!strcmp(el,"Residency")){nbresidency++;depth--;break;}
			if(!strcmp(el,"Overinfection")){nboverinfection++;depth--;break;}
			if(!strcmp(el,"ExecutionProxy")){nbexecution++;depth--;break;}
	}//switch
}


#define MAX_XML_LINE 350
void parseBehaviorDatabase(FILE * bdb){
	char * readdata = calloc(MAX_XML_LINE,sizeof(char)); int datalen;
	int done = 0;		//End of parsing (last token of the file reached)
 
	//Initializing EXPAT parser
	XML_Parser parser = XML_ParserCreate(NULL);
	depth = 0; endbehaviors = 0;
	XML_SetUserData(parser, &depth);
	XML_SetElementHandler(parser, startElement, endElement);

	//Beginning event-driven parsing
	do{
		//Reading database file
		fgets(readdata,MAX_XML_LINE,bdb);
		datalen = (int)strlen(readdata);
		done = feof(bdb);
		//Parsing buffer
		if(!XML_Parse(parser, readdata, datalen, done)){
			printf("[-] Parsing error at line %d: %s\n",
				XML_GetCurrentLineNumber(parser),XML_ErrorString(XML_GetErrorCode(parser)));
			exit(0);
		}
	}while(!done&&!endbehaviors);
	XML_ParserFree(parser);
}
  
